#include "tmdb.h"

#include <QSettings>
#include <QNetworkRequest>
#include <QEventLoop>

#include <qjson/parser.h>

const QString Tmdb::API_MASTER_DOMAIN = "http://api.themoviedb.org";
const QString Tmdb::API_VERSION = "/3";
const QString Tmdb::API_CONFIGURATION = "/configuration";
const QString Tmdb::API_SEARCH_MOVIE = "/search/movie";

Tmdb::Tmdb(QObject *parent) :
    QObject(parent),
    errorCode_(none),
    configOk_(false)
{
    manager_ = new QNetworkAccessManager(this);

    connect(manager_, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(requestFinished(QNetworkReply*)));

    loadConfiguration();
}

///
/// @return     The full Url to load the configuration
///
/// Returns the Url with API key for the request to load
/// the configuration for TMDB
const QUrl Tmdb::getConfigurationUrl()
{
    QString tmp;
    tmp.append(API_MASTER_DOMAIN);
    tmp.append(API_VERSION);
    tmp.append(API_CONFIGURATION);
    tmp.append("?api_key="+apiKey_);

    const QUrl url(tmp);

    return url;
}

///
/// @param  search      The movie search string
///
/// @return     The full Url to search a movie
///
/// Returns the Url with API key for the request to load
/// specified movie data
const QUrl Tmdb::getMovieSearchUrl(const QString &search)
{
    QString tmp;
    tmp.append(API_MASTER_DOMAIN);
    tmp.append(API_VERSION);
    tmp.append(API_SEARCH_MOVIE);
    tmp.append("?api_key="+apiKey_);
    tmp.append("&query="+QUrl::toPercentEncoding(search));

    const QUrl url(tmp);

    return url;
}

///
/// @param  path    The backdrop path for an image at TMDB
///
/// @return         The full Url to the image
///
/// Returns the full api supported irmage url
const QUrl Tmdb::getImageUrl(const QString &path)
{
    QString tmp;
    tmp.append(imageBaseUrl_);
    tmp.append("original");
    tmp.append(path);
    tmp.append("?api_key="+apiKey_);

    const QUrl url(tmp);

    return url;
}

///
/// Load the configuration from TMDB. Its a blocked call.
void Tmdb::loadConfiguration()
{
    QSettings settings(CONFIG_FILE, QSettings::IniFormat);
    apiKey_ = settings.value("tmdb/apikey").toString();

    if (apiKey_.isEmpty()) {
        errorCode_ = fatal;
        errorString_ = tr("No API key configured");
        // Error handling
    }
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkRequest request;
    request.setRawHeader("Accept", "application/json");
    request.setUrl(getConfigurationUrl());

    QNetworkReply *reply = manager->get(request);
    QEventLoop loop;
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    if (reply->error() == QNetworkReply::NoError)
        parseConfigurationRequest(reply);
}

///
/// @param  path    The backdrop path for an image at TMDB
///
/// Loads a Image from TMDB
const QByteArray Tmdb::loadImage(const QString &path)
{
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkRequest request;
    QByteArray result;

    request.setUrl(getImageUrl(path));

    QNetworkReply *reply = manager->get(request);
    QEventLoop loop;
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    if (reply->error() == QNetworkReply::NoError) {
        result = reply->readAll();
    } else {
        qDebug() << Q_FUNC_INFO;
    }

    reply->deleteLater();

    return result;
}

///
/// @param  reply       The response from configuration request
///
/// Parse the TMDB configuration request
void Tmdb::parseConfigurationRequest(QNetworkReply *reply)
{
    QJson::Parser parser;
    bool ok;

    QVariantMap result = parser.parse(reply->readAll(), &ok).toMap();

    if (ok) {
        QVariantMap imageConfig = result["images"].toMap();

        imageBaseUrl_ = imageConfig["base_url"].toString();
        if (!imageBaseUrl_.isEmpty())
            configOk_ = true;
    }

    reply->deleteLater();
}

///
/// @param  search      The movie which be searched on TMDB
///
/// Movie lookup for TMDB
void Tmdb::lookupMovie(Movie *movie)
{
    //qDebug() << Q_FUNC_INFO;
    movie_ = movie;
    QString search = movie_->getTitle()+" "+QVariant(movie_->getYear()).toString();
    //qDebug() << search;
    QNetworkRequest request;
    request.setRawHeader("Accept", "application/json");
    request.setUrl(getMovieSearchUrl(search));

    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkReply *reply = manager->get(request);
    QEventLoop loop;
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    requestFinished(reply);

    //requestData_.insert(request.url().toString(), id);
}

///
/// @param  reply       A pointer the the network response
///
/// Handles the response for each request
void Tmdb::requestFinished(QNetworkReply *reply)
{
    results_.clear();
    if (reply->error() == QNetworkReply::NoError) {
        QJson::Parser parser;
        bool ok;
        QVariantMap result = parser.parse(reply->readAll(), &ok).toMap();
        foreach (QVariant movie, result["results"].toList()) {
            LookupResult res;
            QVariantMap tMovie = movie.toMap();
            qDebug() << "== MOVIE: " << movie_->getTitle() << " ==";
            qDebug() << "Title: " << tMovie["original_title"].toString();
            qDebug() << "ID: " << tMovie["id"].toInt();
            qDebug() << "Image: " << tMovie["backdrop_path"].toString();
            qDebug() << "Year: " << tMovie["release_date"].toString();
            qDebug() << "== MOVIE ==";
            res.cover = loadImage(tMovie["poster_path"].toString());
            res.tmdb_id = tMovie["id"].toInt();
            res.title = tMovie["title"].toString();
            res.year = tMovie["release_date"].toString();
            results_.push_back(res);
        }
    } else {
        qDebug() << reply->errorString();
    }

    reply->deleteLater();
}
